/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package fr.univlille1.ftp;

import it.sauronsoftware.ftp4j.FTPAbortedException;
import it.sauronsoftware.ftp4j.FTPClient;
import it.sauronsoftware.ftp4j.FTPDataTransferException;
import it.sauronsoftware.ftp4j.FTPException;
import it.sauronsoftware.ftp4j.FTPFile;
import it.sauronsoftware.ftp4j.FTPIllegalReplyException;
import it.sauronsoftware.ftp4j.FTPListParseException;
import it.sauronsoftware.ftp4j.listparsers.UnixListParser;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.servlet.http.HttpServletResponse;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Context;
import javax.ws.rs.core.UriInfo;
import javax.ws.rs.Consumes;
import javax.ws.rs.DELETE;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.Response;

/**
 * REST Web Service
 *
 * @author louis
 */
@Path("ftp")
public class FTPBridge {

    @Context
    private UriInfo context;
    
    @Context
    private HttpServletResponse a;
    
    private FTPClient ftpClient;

    public FTPBridge() {
        this.ftpClient = new FTPClient();
        this.ftpClient.addListParser(new UnixListParser());
    }

    public void openFTPConnection(){
        try {
            this.ftpClient.connect("ftp.univ-lille1.fr", 21);
            this.ftpClient.login("Anonymous", "Void");
        } catch (IllegalStateException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPIllegalReplyException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    private void closeFTPConnection() {
        try {
            this.ftpClient.disconnect(true);
        } catch (IllegalStateException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPIllegalReplyException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    private boolean isDirectory(String pathName){
        return pathName.matches(".*..*");
    }
    
    /**
     * Returns just a HelloWorld
     */
    @GET
    @Produces(MediaType.TEXT_HTML)
    public Response helloWorld(){
        String retour = "<html><body>";
        retour += "<h1>Hello World!</h1>";
        retour += "<p>You may want to browse the ";
        retour += "<a href=\""+this.context.getAbsolutePath()+"//\">root directory</a>?</p>";
        retour += "</body></html>";
        return Response.ok(retour, "text/html").build();
    }
    
    /**
     * Depends on ressource :
     * File : retrieves file
     * Directory : sends directory content in html format
     * @return an instance of java.lang.String
     */
    @GET
    @Path("{filePath : .+}")
    public Response doGet(@PathParam("filePath") String filePath) {
        Response response;
        this.openFTPConnection();
        if(this.isDirectory(filePath)){
            response = this.doGetDirectory(filePath);
        }else{
            response = this.doGetFile(filePath);
        }
        this.closeFTPConnection();
        return response;
    }
    
    private Response doGetFile(String filePath){
        try {
            File f = File.createTempFile("FTPBridge", ".tmp");
            Transferer t = new Transferer(true, filePath, this.ftpClient, f);
            t.start();
            try{
                t.join();
            }catch(InterruptedException ex){
                Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
            }
            return Response.ok(f, MediaType.APPLICATION_OCTET_STREAM_TYPE).build();
        } catch (IOException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IllegalStateException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }
    
    private Response doGetDirectory(String filePath){
       String responsestring = "<html><body><h1>Content of directory : "+filePath+"</h1>";
        try{
            FTPFile[] files = this.ftpClient.list(filePath);
            if(!filePath.equals("/")) 
                    responsestring += "d <a href='"+this.context.getAbsolutePath().toASCIIString()+"..'>..</a><br/>";
            for(FTPFile file : files)
                if(file.getType()==FTPFile.TYPE_DIRECTORY){
                    responsestring += "d <a href='"+this.context.getAbsolutePath().toASCIIString()+file.getName()+"/'>"+file.getName()+"</a><br/>";
                }else if(file.getType()==FTPFile.TYPE_LINK){
                    responsestring += "l <a href='"+this.context.getAbsolutePath().toASCIIString()+file.getName()+"/'>"+file.getName()+"</a><br/>";                    
                }else{
                    responsestring += "f <a href='"+this.context.getAbsolutePath().toASCIIString()+file.getName()+"'>"+file.getName()+"</a><br/>";
                }
        } catch(Exception e){
            responsestring += "<p>Erreur lors de la communication avec le serveur FTP...</p>";
        }
        responsestring += "</body></html>";
        return Response.ok(responsestring, "text/html").build();
    }

    /**
     * Uploads a file
     * @return an instance of java.lang.String
     */
    @PUT
    @Path("{filePath : .+}")
    @Consumes("application/octet-stream")
    public void doPut(@PathParam("filePath") String filePath, InputStream in) {
        this.openFTPConnection();
        try {
            this.ftpClient.upload(filePath, in, 0, 0, null);
        } catch (IllegalStateException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPIllegalReplyException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPDataTransferException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPAbortedException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        }
        this.closeFTPConnection();
    }
    
    /**
     * Crée un dossier 
     * @return an instance of java.lang.String
     */
    @POST
    @Path("{filePath : .+}")
    public void doPost(@PathParam("filePath") String filePath){
        this.openFTPConnection();
        try {
            this.ftpClient.createDirectory(filePath);
        } catch (IllegalStateException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPIllegalReplyException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        }
        this.closeFTPConnection();
    }
        
    /**
     * Depends on ressource :
     * File : supprime le fichier
     * Directory : supprime récursivement le dossier et son contenu
     * @return an instance of java.lang.String
     */
    @DELETE
    @Path("{filePath : .+}")
    public void doDelete(@PathParam("filePath") String filePath){
        this.openFTPConnection();
        if(this.isDirectory(filePath)){
            this.doDeleteDirectory(filePath);
        }else{
            this.doDeleteFile(filePath);
        }
        this.closeFTPConnection();
    }
    
    private void doDeleteFile(String filePath){
        try {
            this.ftpClient.deleteFile(filePath);
        } catch (IllegalStateException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPIllegalReplyException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        }
    }
    
    private void doDeleteDirectory(String filePath){
        try {
            this.ftpClient.deleteDirectory(filePath);
        } catch (IllegalStateException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (IOException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPIllegalReplyException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        } catch (FTPException ex) {
            Logger.getLogger(FTPBridge.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

}
